package com.wxm.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.function.BiFunction;

/**
 * <p>
 *      Http工具类
 * </p>
 *
 * @author: wxm
 * @Date: 2023/4/7
 */
@Slf4j
public final class HttpUtils {
    private HttpUtils(){}
    public static <T, E> E postParamSend(String url, JSONObject params, JSONObject header, Class<T> aClass, BiFunction<String, Class<T>, E> processor) {
        //获取httpClient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //URL
        url = url + HttpUtils.disposeGetParams(params);
        // 获取请求对象
        HttpPost httpPost = new HttpPost(url);
        //设置头部
        HttpUtils.setHeader(httpPost,header);
        //打印记录日志
        HttpUtils.sendLog("POST Param",url,header,params.toJSONString());
        String result = null;
        try {
            HttpResponse response = httpClient.execute(httpPost);
            //校验返回结果
            HttpUtils.checkResponseStatusCode(response);
            HttpEntity entity = response.getEntity();
            result = EntityUtils.toString(entity);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //结果转换处理
        return HttpUtils.resultResolver(result,aClass,processor);
    }

    /**
     * 处理GET请求的参数 会对参数进行 URLEncoder.encode处理
     * @param params 参数
     * @return String 格式: 有值："?key=xxx&value:12" 没值: ""
     */
    private static String disposeGetParams(JSONObject params) {
        return getParams(params,true);
    }

    /**
     * 处理GET请求的参数
     * @param params 参数
     * @param urlEncoderTag 是否对参数进行 URLEncoder.encode处理
     * @return String
     */
    private static String getParams(JSONObject params,Boolean urlEncoderTag){
        //设置参数
        StringBuilder paramsStr = new StringBuilder();
        if (params != null) {
            int index = 0;
            for (Map.Entry<String, Object> stringObjectEntry : params.getInnerMap().entrySet()) {
                if (index != 0) {
                    //不是第一个都先拼上 &
                    paramsStr.append("&");
                } else {
                    //第一个参数拼上 ?
                    paramsStr.append("?");
                    index = 1;
                }
                //取出map中的值 key=value进行拼接 urlEncoderTag则将参数进行URLEncoder.encode
                try {
                    paramsStr.append(stringObjectEntry.getKey()).append("=").append(
                            urlEncoderTag? URLEncoder.encode(stringObjectEntry.getValue()==null ? "" : stringObjectEntry.getValue().toString(), "UTF-8"):stringObjectEntry.getValue().toString()
                    );
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        return paramsStr.toString();
    }

    /**
     * 设置请求头
     * @param httpRequestBase http
     * @param header 头部JSON
     */
    private static void setHeader(HttpRequestBase httpRequestBase, JSONObject header){
        if (!CollectionUtils.isEmpty(header)){
            Map<String, Object> innerMap = header.getInnerMap();
            innerMap.forEach((key, value) -> httpRequestBase.setHeader(key, value.toString()));
        }
    }

    /**
     * 请求前准备好后的日志输出
     * @param utl URL
     * @param header 头部信息
     * @param params 参数信息
     * @param <T> T
     * @param <E> T/List<T>
     */
    private static <T,E> void sendLog(String method,String utl,JSONObject header,String params){
        log.info("{} 请求已经准备就绪 \nURL:{} \nHeader:{} \nParam:{}",method, utl, header, params);
    }

    /**
     * 处理请求状态码 判断是否成功
     * @param response response
     */
    private static void checkResponseStatusCode(HttpResponse response){
        // 获得状态码  200 成功      404 为找到路径         500 后台程序错误  。。。。
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 404){
            R.exception("404 未找到路径");
        }else if (statusCode == 500){
            R.exception("500 三方服务异常");
        }
    }

    /**
     * 返回结果解析
     * @param result 返回结果字符串
     * @param aClass 解析Class类型
     * @param processor 解析器方法
     * @param <T> T
     * @param <E> T/List<T>
     * @return 返回期望类型的对象或集合
     */
    private static <T,E> E resultResolver(String result,Class<T> aClass ,BiFunction<String, Class<T>, E> processor){
        E apply = processor.apply(result,aClass);
        log.info("\n返回数据:{}\n解析类型:{}\n处理结果:{}",result,aClass,apply.toString());
        return apply;
    }
}
